package com.suke.money.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.money.suke.utils.Constants;
import com.suke.money.mapper.FinanceAccountMapper;
import com.suke.money.mapper.UserMapper;
import com.suke.money.model.FinanceAccount;
import com.suke.money.model.User;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @Author: liush
 * @CreateTime: 2022-11-20  16:27
 * @Description: 用户业务实现类
 */
@Service(interfaceClass = UserService.class, version = "1.0.0", timeout = 20000)
@Component
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;

    @Autowired
    FinanceAccountMapper financeAccountMapper;

    @Autowired
    RedisTemplate redisTemplate;

    //查询 平台总人数
    @Override
    public Long queryUserCount() {
        //从redis缓存中获取 平台总人数
        Long userCount = (Long) redisTemplate.opsForValue().get(Constants.USER_COUNT);
        //判断缓存中是否有数据
        if (userCount == null) {
            //设置同步代码块
            synchronized (this) {
                //从redis缓存中获取 平台总人数
                userCount = (Long) redisTemplate.opsForValue().get(Constants.USER_COUNT);
                //双重检测判断缓存中是否有数据
                if (userCount == null) {
                    //从数据库查询 平台总人数
                    userCount = userMapper.selectUserCount();
                    //将值存放到redis缓存中
                    redisTemplate.opsForValue().set(Constants.USER_COUNT, userCount, 30, TimeUnit.SECONDS);
                    System.out.println("(×)平台总人数-缓存未命中");
                } else {
                    System.out.println("(√)平台总人数-缓存命中");
                }
            }
        } else {
            System.out.println("(√)平台总人数-缓存命中");
        }
        return userMapper.selectUserCount();
    }

    //注册：根据手机号码 查询用户 数量
    @Override
    public Integer queryUserCountByPhone(String phone) {
        return userMapper.selectUserCountByPhone(phone);
    }

    //注册新用户：1.用户表插入一条记录 2.注册添加888
    @Override
    public User register(String phone, String loginPassword) {
        //1.用户表插入一条记录
        User user = new User();
        user.setPhone(phone);
        user.setLoginPassword(loginPassword);
        user.setAddTime(new Date());
        int num = userMapper.insertSelective(user);
        //根据手机号获取注册用户信息
        User userByPhone = userMapper.selectUserByPhone(phone);
        if (num == 1) {
            //不影响主线程 快速注册的性能
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //2、用户添加888
                    FinanceAccount financeAccount = new FinanceAccount();
                    financeAccount.setAvailableMoney(888d);
                    financeAccount.setUid(userByPhone.getId());
                    financeAccountMapper.insertSelective(financeAccount);
                }
            }).start();
            return userByPhone;
        }
        return null;
    }

    //实名认证：更新用户信息
    @Override
    public int realName(User rUser) {
        return userMapper.updateByPrimaryKeySelective(rUser);
    }

    //登录验证
    @Override
    public User login(String phone, String loginPassword) {
        User user = userMapper.selectUserByPhoneAndPasswd(phone, loginPassword);
        //交给线程池处理最后登录时间,目的：保证用户登录快速成功！
        if (ObjectUtils.allNotNull(user)) {
            ExecutorService executorService = Executors.newFixedThreadPool(16);
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    user.setLastLoginTime(new Date());
                    userMapper.updateByPrimaryKeySelective(user);
                }
            });
        }
        return user;
    }
    /*
     * 线程池的基本思想还是一种对象池的思想，开辟一块内存空间，
     * 里面存放了众多(未死亡)的线程，池中线程执行调度由池管理器来处理。
     * 当有线程任务时，从池中取一个，执行完成后线程对象归池，
     * 这样可以避免反复创建线程对象所带来的性能开销，节省了系统的资源。
     * */

    //更新 用户头像
    @Override
    public void insertHeaderImage(User user) {
        userMapper.updateByPrimaryKeySelective(user);
    }
}
